#include "uart_unix.h"

#include <stdio.h>
#include <fcntl.h>
#include <assert.h>
#include <termios.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/types.h>
#include <errno.h>

int pyfree::uart_open(int &fd,const char *name)
{
    //检测串口路径是否存在
    assert(name);								
    //以读写形式、不将此终端作为此进程的终端控制器、非阻塞的形式打开串口
    fd = open(name,O_RDWR|O_NOCTTY|O_NDELAY);	
    if(fd == -1)
    {
        char e_buf[64]={0};
        sprintf(e_buf,"uart open %s failed!",name);
        perror(e_buf);
        return -1;
    }
    //设置串口非阻塞，因为这里是以非阻塞形式打开的，第三个参数为0，返回值：成功返回0，失败返回-1，失败原因存入errno
    if(fcntl(fd,F_SETFL,0)<0)						
    {
        perror("fcntl failed!");
        return -1;
    }
    return fd;
};

int pyfree::uart_config(int fd,int baude,int c_flow, int bits, char parity, int stop)
{
    struct termios uart;
    //用于获取termios结构体属性。成功返回0，失败返回非0
    if(tcgetattr(fd,&uart)!=0)
    {
        perror("tcgetattr failed!");
        return -1;
    }

    switch(baude)
    {
    case 4800:
        cfsetispeed(&uart,B4800);//设置输入波特率
        cfsetospeed(&uart,B4800);//设置输出波特率
        break;
    case 9600:
        cfsetispeed(&uart,B9600);
        cfsetospeed(&uart,B9600);
        break;
    case 19200:
        cfsetispeed(&uart,B19200);
        cfsetospeed(&uart,B19200);
        break;
    case 38400:
        cfsetispeed(&uart,B38400);
        cfsetospeed(&uart,B38400);
        break;
    default:
        fprintf(stderr,"Unknown baude!");
        return -1;
    }
    switch(c_flow)
    {
    case 'N':
    case 'n':
        uart.c_cflag &= ~CRTSCTS;//不进行硬件流控制
        break;
    case 'H':
    case 'h':
        uart.c_cflag |= CRTSCTS;//进行硬件流控制
        break;
    case 'S':
    case 's':
        uart.c_cflag |= (IXON | IXOFF | IXANY);//进行软件流控制
        break;
    default:
        fprintf(stderr,"Unknown c_cflag");
        return -1;
    }
    switch(bits)
    {
    case 5:
        uart.c_cflag &= ~CSIZE;//屏蔽其他标志位
        uart.c_cflag |= CS5;//数据位为5位
        break;
    case 6:
        uart.c_cflag &= ~CSIZE;
        uart.c_cflag |= CS6;
        break;
    case 7:
        uart.c_cflag &= ~CSIZE;
        uart.c_cflag |= CS7;
        break;
    case 8:
        uart.c_cflag &= ~CSIZE;
        uart.c_cflag |= CS8;
      break;
    default:
        fprintf(stderr,"Unknown bits!");
        return -1;
    }
    switch(parity)
    {
    case 'n':
    case 'N':
        uart.c_cflag &= ~PARENB;//PARENB：产生奇偶校验
        uart.c_cflag &= ~INPCK;//INPCK：使奇偶校验起作用
        break;
    case 's':
    case 'S':
        uart.c_cflag &= ~PARENB;
        uart.c_cflag &= ~CSTOPB;//使用两位停止位
        break;
    case 'o':
    case 'O':
        uart.c_cflag |= PARENB;
        uart.c_cflag |= PARODD;//使用奇校验
        uart.c_cflag |= INPCK;
        uart.c_cflag |= ISTRIP;//使字符串剥离第八个字符，即校验位
        break;
    case 'e':
    case 'E':
        uart.c_cflag |= PARENB;
        uart.c_cflag &= ~PARODD;//非奇校验，即偶校验
        uart.c_cflag |= INPCK;
        uart.c_cflag |= ISTRIP;
        break;
    default:
        fprintf(stderr,"Unknown parity!\n");
        return -1;
    }
    switch(stop)
    {
    case 1:
        uart.c_cflag &= ~CSTOPB;//CSTOPB：使用两位停止位
        break;
    case 2:
        uart.c_cflag |= CSTOPB;
        break;
    default:
        fprintf(stderr,"Unknown stop!\n");
        return -1;
    }

    uart.c_oflag &= ~OPOST;//OPOST:表示数据经过处理后输出
    if(tcsetattr(fd,TCSANOW,&uart)<0)//激活配置，失败返回-1
    {
        return -1;
    }

    uart.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG );//使串口工作在原始模式下
    uart.c_cc[VTIME] = 0;//设置等待时间为0
    uart.c_cc[VMIN] = 1;//设置最小接受字符为1
    tcflush(fd,TCIFLUSH);//清空输入缓冲区
    if(tcsetattr(fd,TCSANOW,&uart)<0)//激活配置
    {
        perror("tcgetattr failed!");
        return -1;
    }
    return 0;
}

int pyfree::uart_read(int fd, char *r_buf, int lenth, int time_out_ms/*=1000*/)
{
    fd_set rfds;
    struct timeval time;
    ssize_t cnt = 0;
    /*将读文件描述符加入描述符集合*/
    FD_ZERO(&rfds);
    FD_SET(fd,&rfds);
    /*设置超时为*/
    time.tv_sec = (time_t)(time_out_ms/1000);
    time.tv_usec = (long)1000*(time_out_ms%1000);
    /*实现多路IO*/
    int ret = select(fd+1, &rfds ,NULL, NULL, &time);
    switch (ret) {
    case -1:
        fprintf(stderr,"select error!\n");
        break;
    case 0:
        fprintf(stderr, "time over!\n");
        break;
    default:
        cnt = read(fd, r_buf, lenth);
        if(cnt == -1)
        {
            fprintf(stderr, "read failed!\n");
            return -1;
        }
        return cnt;
    }
    return ret;
}

int pyfree::uart_write(int fd, char *r_buf, int lenth, int time_out_ms/*=1000*/)//串口写入数据
{
    fd_set rfds;
    struct timeval time;
    ssize_t cnt = 0;
    /*将读文件描述符加入描述符集合*/
    FD_ZERO(&rfds);
    FD_SET(fd,&rfds);
    /*设置超时为*/
    time.tv_sec = (time_out_ms/1000);
    time.tv_usec = 1000*(time_out_ms%1000);
    /*实现多路IO*/
    int ret = select(fd+1, &rfds ,NULL, NULL, &time);
    switch (ret) {
    case -1:
        fprintf(stderr,"select error!\n");
        break;
    case 0:
        fprintf(stderr, "time over!\n");
        break;
    default:
        cnt = write(fd, r_buf, lenth);
        if(cnt!=lenth)
        {
            fprintf(stderr, "write failed!\n");
            return -1;
        }
        return cnt;
    }
    return ret;
}

int pyfree::uart_clear(int fd,int model)
{
    assert(fd);
    int ret = tcflush(fd,model);
    if(ret<0){
        fprintf(stderr, "tcflush failed!\n");
    }
    return ret;
}

int pyfree::uart_close(int fd)
{
    assert(fd);//assert先检查文件描述符是否存在
    close(fd);
    return 0;
}


